﻿#pragma once

#include "../df.h"
#include "httpHead.h"


namespace df
{
	using namespace sdf;

	enum HttpType{
		typeHttp,
		typeHttps,
	};


	class HttpParse
	{
	public:

		//url Encode表
		static CCa EncodeTable[256];


		//************************************
		// Method:    Encode URI Component编码,排除字符 !'()*-._~0-9a-zA-Z
		// Returns:   void
		// Parameter: const CCa & from
		// Parameter: std::string & to
		//************************************
		inline static void Encode(const CCa & from, std::string & to)
		{
			for (char c : from)
			{
				to << EncodeTable[(uint8_t)c];
			}
		}
		//************************************
		// Method:    ParseHttpURL 解析url中的域名与端口
		// Returns:   df::Http::Type http或https
		// Parameter: const CCa & url
		// Parameter: std::string & hostName 域名结果
		// Parameter: uint16_t & port 端口结果
		// Parameter: std::string & urlPara url参数
		//************************************
		static HttpType ParseHttpURL(const CCa & url, std::string & hostName, uint16_t & port, std::string & urlPara)
		{

			HttpType type = HttpType::typeHttp;
			intptr_t i = 0;
			port = 80;

			if (url.length() > 7 && url.IsMatch("http://", 0, false)){
				i += 7;
			}
			else if (url.length() > 8 && url.IsMatch("https://", 0, false)){
				type = HttpType::typeHttps;
				i += 8;
			}


			for (; i < url.length(); i++)
			{
				char c = url[i];
				if (c == ':')
				{
					i += 1;
					df::StrToVar(ReadNumber(url, i), port);
					break;
				}
				else if (c == '/')
					break;

				hostName << c;
			}

			urlPara << CCa(url.char_ + i, url.length() - i);

			return type;
		}

		inline static CCa ReadNumber(CCa url, intptr_t & i)
		{
			CCa port(url.c_str() + i, 0);
			for (; i < url.length(); i++)
			{
				char c = url[i];

				if (!CCa::IsInteger(c))
					break;

				port.length_++;
			}
			return port;
		}


		template<class _Pair>
		inline static void AddformKeyVal(const _Pair & pair, CCa boundary, std::string & out)
		{
			out << "--" << boundary << "\r\n"
				"Content-Disposition: form-data; name=\"" << pair.first << "\"\r\n\r\n";
			out << pair.second << "\r\n";
		}

		inline static void HeadMapToStr(HttpHead & head, std::string & out)
		{
			for (auto & para : head.GetMap())
			{
				if (para.first == HTTP_keyMethod)
					continue;

				out << para.first << ": " << para.second;

				// 				if (port != 80 && para.first == HttpHead::keyHost())
				// 					out << ":" << port;

				out << "\r\n";
			}
			out << "\r\n";
		}

		//************************************
		// Method:    getHttpHeadSize 从缓冲区中获取http头长度
		// Returns:   intptr_t 大于0成功返回http头长度,<=0表示失败
		// Parameter: void * buf
		// Parameter: intptr_t size
		//************************************
		inline static intptr_t getHttpHeadSize(const void * buf, intptr_t size)
		{
			//查找\r\n\r\n判断http头是否完整
			char * hPtr = (char *)buf;
			for (int i = 0; i < size - 4; i += 1)
			{
				if (*(uint32_t*)(hPtr + i) == *(uint32_t*)"\r\n\r\n")
				{
					return i + 4;
				}
			}

			return 0;
		}

		//************************************
		// Method:    HasRN 查找是否含有\r\n
		// Returns:   intptr_t
		// Parameter: const void * buf
		// Parameter: intptr_t size
		//************************************
		inline static intptr_t HasRN(const void * buf, intptr_t size)
		{
			//查找是否含有\r\n
			char * hPtr = (char *)buf;
			for (int i = 0; i < size - 2; i += 1)
			{
				if (*(uint16_t*)(hPtr + i) == *(uint16_t*)"\r\n")
				{
					return i + 2;
				}
			}

			return 0;
		}

		inline static void SkipN(const char * sPtr, intptr_t & i)
		{
			if (sPtr[i + 1] == '\n')
				i += 2;
		}
		inline static void SkipSpace(const char * sPtr, intptr_t & i)
		{
			if (sPtr[i + 1] == ' ')
				i += 2;
		}


		//************************************
		// Method:    HeadStrToMap 将http头解析至out
		// Returns:   bool
		// Parameter: const void * str http头原始数据
		// Parameter: int32_t size 原始数据长度
		// Parameter: HttpHead & out 解析结果
		// Parameter: ErrWrap err
		//************************************
		static bool HeadStrToMap(const void * str, int32_t size, HttpHead & out, ErrWrap err = nullptr)
		{
			auto sPtr = (const char*)str;

			if (!CCa(sPtr, size).IsMatch("http/", 0, false))
			{
				DF_ERRLOG(err, ErrCode::HttpHeadInvalid, "非法的http头,缺少HTTP/");
				return false;
			}

			std::string key, val;

			//http协议版本部分放入method中
			intptr_t i = 0;
			for (; i < size; i++)
			{
				if (sPtr[i] == '\r')
				{
					SkipN(sPtr, i);
					break;
				}

				val << sPtr[i];
			}
			out.GetMap()[HTTP_keyMethod] = std::move(val);

			for (; i < size; i++)
			{

				if (sPtr[i] == '\n' || sPtr[i] == '\r')
					continue;

				//值
				if (sPtr[i] == ':')
				{
					SkipSpace(sPtr, i);

					//初始化值
					for (; i < size; i++)
					{
						//解析出键值对
						if (sPtr[i] == '\r')
						{
							out.GetMap()[std::move(key)] = std::move(val);

							SkipN(sPtr, i);

							key.clear();
							i--;
							break;
						}
						else
							val << sPtr[i];
					}

					continue;
				}
				key << sPtr[i];
			}


			return true;
		}

		DF_DISABLE_COPY_ASSIGN(HttpParse);
	};

	DF_STATIC_INIT CCa  HttpParse::EncodeTable[256] = {
		CCa("%00", 3),
		CCa("%01", 3),
		CCa("%02", 3),
		CCa("%03", 3),
		CCa("%04", 3),
		CCa("%05", 3),
		CCa("%06", 3),
		CCa("%07", 3),
		CCa("%08", 3),
		CCa("%09", 3),
		CCa("%0A", 3),
		CCa("%0B", 3),
		CCa("%0C", 3),
		CCa("%0D", 3),
		CCa("%0E", 3),
		CCa("%0F", 3),
		CCa("%10", 3),
		CCa("%11", 3),
		CCa("%12", 3),
		CCa("%13", 3),
		CCa("%14", 3),
		CCa("%15", 3),
		CCa("%16", 3),
		CCa("%17", 3),
		CCa("%18", 3),
		CCa("%19", 3),
		CCa("%1A", 3),
		CCa("%1B", 3),
		CCa("%1C", 3),
		CCa("%1D", 3),
		CCa("%1E", 3),
		CCa("%1F", 3),
		CCa("%20", 3),
		CCa("%21", 3),
		CCa("%22", 3),
		CCa("%23", 3),
		CCa("%24", 3),
		CCa("%25", 3),
		CCa("%26", 3),
		CCa("'", 1),
		CCa("(", 1),
		CCa(")", 1),
		CCa("*", 1),
		CCa("%2B", 3),
		CCa("%2C", 3),
		CCa("-", 1),
		CCa(".", 1),
		CCa("%2F", 3),
		CCa("0", 1),
		CCa("1", 1),
		CCa("2", 1),
		CCa("3", 1),
		CCa("4", 1),
		CCa("5", 1),
		CCa("6", 1),
		CCa("7", 1),
		CCa("8", 1),
		CCa("9", 1),
		CCa("%3A", 3),
		CCa("%3B", 3),
		CCa("%3C", 3),
		CCa("%3D", 3),
		CCa("%3E", 3),
		CCa("%3F", 3),
		CCa("%40", 3),
		CCa("A", 1),
		CCa("B", 1),
		CCa("C", 1),
		CCa("D", 1),
		CCa("E", 1),
		CCa("F", 1),
		CCa("G", 1),
		CCa("H", 1),
		CCa("I", 1),
		CCa("J", 1),
		CCa("K", 1),
		CCa("L", 1),
		CCa("M", 1),
		CCa("N", 1),
		CCa("O", 1),
		CCa("P", 1),
		CCa("Q", 1),
		CCa("R", 1),
		CCa("S", 1),
		CCa("T", 1),
		CCa("U", 1),
		CCa("V", 1),
		CCa("W", 1),
		CCa("X", 1),
		CCa("Y", 1),
		CCa("Z", 1),
		CCa("%5B", 3),
		CCa("%5C", 3),
		CCa("%5D", 3),
		CCa("%5E", 3),
		CCa("_", 1),
		CCa("%60", 3),
		CCa("a", 1),
		CCa("b", 1),
		CCa("c", 1),
		CCa("d", 1),
		CCa("e", 1),
		CCa("f", 1),
		CCa("g", 1),
		CCa("h", 1),
		CCa("i", 1),
		CCa("j", 1),
		CCa("k", 1),
		CCa("l", 1),
		CCa("m", 1),
		CCa("n", 1),
		CCa("o", 1),
		CCa("p", 1),
		CCa("q", 1),
		CCa("r", 1),
		CCa("s", 1),
		CCa("t", 1),
		CCa("u", 1),
		CCa("v", 1),
		CCa("w", 1),
		CCa("x", 1),
		CCa("y", 1),
		CCa("z", 1),
		CCa("%7B", 3),
		CCa("%7C", 3),
		CCa("%7D", 3),
		CCa("~", 1),
		CCa("%7F", 3),
		CCa("%80", 3),
		CCa("%81", 3),
		CCa("%82", 3),
		CCa("%83", 3),
		CCa("%84", 3),
		CCa("%85", 3),
		CCa("%86", 3),
		CCa("%87", 3),
		CCa("%88", 3),
		CCa("%89", 3),
		CCa("%8A", 3),
		CCa("%8B", 3),
		CCa("%8C", 3),
		CCa("%8D", 3),
		CCa("%8E", 3),
		CCa("%8F", 3),
		CCa("%90", 3),
		CCa("%91", 3),
		CCa("%92", 3),
		CCa("%93", 3),
		CCa("%94", 3),
		CCa("%95", 3),
		CCa("%96", 3),
		CCa("%97", 3),
		CCa("%98", 3),
		CCa("%99", 3),
		CCa("%9A", 3),
		CCa("%9B", 3),
		CCa("%9C", 3),
		CCa("%9D", 3),
		CCa("%9E", 3),
		CCa("%9F", 3),
		CCa("%A0", 3),
		CCa("%A1", 3),
		CCa("%A2", 3),
		CCa("%A3", 3),
		CCa("%A4", 3),
		CCa("%A5", 3),
		CCa("%A6", 3),
		CCa("%A7", 3),
		CCa("%A8", 3),
		CCa("%A9", 3),
		CCa("%AA", 3),
		CCa("%AB", 3),
		CCa("%AC", 3),
		CCa("%AD", 3),
		CCa("%AE", 3),
		CCa("%AF", 3),
		CCa("%B0", 3),
		CCa("%B1", 3),
		CCa("%B2", 3),
		CCa("%B3", 3),
		CCa("%B4", 3),
		CCa("%B5", 3),
		CCa("%B6", 3),
		CCa("%B7", 3),
		CCa("%B8", 3),
		CCa("%B9", 3),
		CCa("%BA", 3),
		CCa("%BB", 3),
		CCa("%BC", 3),
		CCa("%BD", 3),
		CCa("%BE", 3),
		CCa("%BF", 3),
		CCa("%C0", 3),
		CCa("%C1", 3),
		CCa("%C2", 3),
		CCa("%C3", 3),
		CCa("%C4", 3),
		CCa("%C5", 3),
		CCa("%C6", 3),
		CCa("%C7", 3),
		CCa("%C8", 3),
		CCa("%C9", 3),
		CCa("%CA", 3),
		CCa("%CB", 3),
		CCa("%CC", 3),
		CCa("%CD", 3),
		CCa("%CE", 3),
		CCa("%CF", 3),
		CCa("%D0", 3),
		CCa("%D1", 3),
		CCa("%D2", 3),
		CCa("%D3", 3),
		CCa("%D4", 3),
		CCa("%D5", 3),
		CCa("%D6", 3),
		CCa("%D7", 3),
		CCa("%D8", 3),
		CCa("%D9", 3),
		CCa("%DA", 3),
		CCa("%DB", 3),
		CCa("%DC", 3),
		CCa("%DD", 3),
		CCa("%DE", 3),
		CCa("%DF", 3),
		CCa("%E0", 3),
		CCa("%E1", 3),
		CCa("%E2", 3),
		CCa("%E3", 3),
		CCa("%E4", 3),
		CCa("%E5", 3),
		CCa("%E6", 3),
		CCa("%E7", 3),
		CCa("%E8", 3),
		CCa("%E9", 3),
		CCa("%EA", 3),
		CCa("%EB", 3),
		CCa("%EC", 3),
		CCa("%ED", 3),
		CCa("%EE", 3),
		CCa("%EF", 3),
		CCa("%F0", 3),
		CCa("%F1", 3),
		CCa("%F2", 3),
		CCa("%F3", 3),
		CCa("%F4", 3),
		CCa("%F5", 3),
		CCa("%F6", 3),
		CCa("%F7", 3),
		CCa("%F8", 3),
		CCa("%F9", 3),
		CCa("%FA", 3),
		CCa("%FB", 3),
		CCa("%FC", 3),
		CCa("%FD", 3),
		CCa("%FE", 3),
		CCa("%FF", 3),
	};

}
